﻿namespace System.ServiceModel.DomainServices.Client
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;

    internal abstract class ValidationResultCollection : ICollection<ValidationResult>, IEnumerable<ValidationResult>, IEnumerable
    {
        private bool _hasErrors = false;
        private object _parent;
        private MetaType _parentMetaType;
        private IEnumerable<string> _propertiesInError = Enumerable.Empty<string>();
        private List<ValidationResult> _results = new List<ValidationResult>();

        internal ValidationResultCollection(object parent)
        {
            this._parent = parent;
            if (this._parent != null)
            {
                this._parentMetaType = MetaType.GetMetaType(this._parent.GetType());
            }
        }

        public void Add(ValidationResult item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            IEnumerable<string> memberNames = item.MemberNames;
            if (!memberNames.Any<string>())
            {
                string[] strArray = new string[1];
                memberNames = strArray;
            }
            this._results.Add(item);
            this.OnAdd(item);
            this.OnCollectionChanged(memberNames);
        }

        public void Clear()
        {
            this.OnClear();
            if (this.Count > 0)
            {
                this._results.Clear();
                this.OnCollectionChanged(Enumerable.Empty<string>());
            }
        }

        public bool Contains(ValidationResult item)
        {
            return this._results.Contains(item);
        }

        public void CopyTo(ValidationResult[] array, int arrayIndex)
        {
            this._results.CopyTo(array, arrayIndex);
        }

        public IEnumerator<ValidationResult> GetEnumerator()
        {
            return this._results.GetEnumerator();
        }

        private static IEnumerable<string> GetPropertiesInError(IEnumerable<ValidationResult> errors)
        {
            IEnumerable<string> first = Enumerable.Empty<string>();
            if (errors != null)
            {
                first = from e in errors select e.MemberNames;
                if (Enumerable.Any<ValidationResult>(errors, (Func<ValidationResult, bool>) (e => !e.MemberNames.Any<string>())))
                {
                    first = first.Union<string>(new string[1]);
                }
            }
            return first.ToArray<string>();
        }

        protected virtual void OnAdd(ValidationResult item)
        {
        }

        protected virtual void OnClear()
        {
            if ((this._parent != null) && this._parentMetaType.HasComplexMembers)
            {
                foreach (MetaMember member in from p in this._parentMetaType.DataMembers
                    where p.IsComplex
                    select p)
                {
                    object obj2 = member.GetValue(this._parent);
                    if (obj2 != null)
                    {
                        if (!member.IsCollection)
                        {
                            ComplexObject obj3 = (ComplexObject) obj2;
                            obj3.ValidationErrors.Clear();
                        }
                        else
                        {
                            foreach (ComplexObject obj4 in (IEnumerable) obj2)
                            {
                                obj4.ValidationErrors.Clear();
                            }
                            continue;
                        }
                    }
                }
            }
        }

        protected virtual void OnCollectionChanged()
        {
        }

        private void OnCollectionChanged(IEnumerable<string> propertiesAffected)
        {
            bool flag = this._hasErrors;
            IEnumerable<string> first = this._propertiesInError;
            this._hasErrors = this.Count > 0;
            this._propertiesInError = GetPropertiesInError(this).Distinct<string>();
            if (this._hasErrors != flag)
            {
                this.OnHasErrorsChanged();
            }
            IEnumerable<string> enumerable2 = first.Except<string>(this._propertiesInError);
            IEnumerable<string> second = this._propertiesInError.Except<string>(first);
            foreach (string str in enumerable2.Union<string>(second).Union<string>(propertiesAffected))
            {
                this.OnPropertyErrorsChanged(str);
            }
            this.OnCollectionChanged();
        }

        protected virtual void OnHasErrorsChanged()
        {
        }

        protected virtual void OnPropertyErrorsChanged(string propertyName)
        {
        }

        protected virtual void OnRemove(ValidationResult item)
        {
        }

        public bool Remove(ValidationResult item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            IEnumerable<string> memberNames = item.MemberNames;
            if (!this._results.Remove(item))
            {
                return false;
            }
            if (!memberNames.Any<string>())
            {
                string[] strArray = new string[1];
                memberNames = strArray;
            }
            this.OnRemove(item);
            this.OnCollectionChanged(memberNames);
            return true;
        }

        internal void ReplaceErrors(IEnumerable<ValidationResult> newResults)
        {
            if ((this.Count > 0) || newResults.Any<ValidationResult>())
            {
                this._results.Clear();
                this._results.AddRange(newResults);
                this.OnCollectionChanged(GetPropertiesInError(newResults));
            }
        }

        internal void ReplaceErrors(string propertyName, IEnumerable<ValidationResult> newResults)
        {
            List<string> affectedMembers = (from p in this
                select p.MemberNames into p
                where (p != null) && p.StartsWith(propertyName + ".", StringComparison.Ordinal)
                select p).ToList<string>();
            affectedMembers.Add(propertyName);
            IEnumerable<ValidationResult> source = from r in this
                where r.MemberNames.Intersect<string>(affectedMembers).Any<string>()
                select r;
            if ((source.Count<ValidationResult>() > 0) || (newResults.Count<ValidationResult>() > 0))
            {
                IEnumerable<ValidationResult> collection = this.Except<ValidationResult>(source).ToArray<ValidationResult>();
                this._results.Clear();
                this._results.AddRange(collection);
                this._results.AddRange(newResults);
                this.OnCollectionChanged(GetPropertiesInError(newResults).Union<string>(affectedMembers));
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        public int Count
        {
            get
            {
                return this._results.Count;
            }
        }

        public bool IsReadOnly
        {
            get
            {
                return false;
            }
        }
    }
}

